package com.flyco.modules.home.controller;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.flyco.common.api.vo.Result;
import com.flyco.common.system.vo.LoginUser;
import com.flyco.common.util.DateUtils;
import com.flyco.common.util.oConvertUtils;
import com.flyco.modules.home.vo.HomeOrderVO;
import com.flyco.modules.home.vo.OrderTotalPayAmountVO;
import com.flyco.modules.oms.service.IOmsOrderService;
import com.flyco.modules.stm.entity.StmKpiCalendar;
import com.flyco.modules.stm.entity.StmKpiStore;
import com.flyco.modules.stm.entity.StmStoreInfo;
import com.flyco.modules.stm.service.IStmKpiCalendarService;
import com.flyco.modules.stm.service.IStmKpiStoreService;
import com.flyco.modules.stm.service.IStmOrderService;
import com.flyco.modules.stm.service.IStmStoreInfoService;
import com.flyco.modules.ums.service.IUmsMemberService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Api(tags = "首页")
@RestController
@RequestMapping("/f/home/homePage")
@Slf4j
public class HomePageController {

    @Autowired
    private IOmsOrderService omsOrderService;
    @Autowired
    private IUmsMemberService umsMemberService;
    @Autowired
    private IStmOrderService stmOrderService;
    @Autowired
    private IStmStoreInfoService stmStoreInfoService;
    @Autowired
    private IStmKpiStoreService stmKpiStoreService;
    @Autowired
    private IStmKpiCalendarService stmKpiCalendarService;

    /**
     * 首页统计
     *
     * @return
     */
    @ApiOperation(value="订单-首页统计", notes="订单-首页统计")
    @GetMapping(value = "/indexInit")
    public Result<?> indexInit() {
        Map<String, Object> map = new HashMap<>();
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        map.put("member",umsMemberService.indexMemberInit());
        map.put("online",omsOrderService.indexOrderInit());
        //map.put("onlineBarData",omsOrderService.indexOrderBar());
        List<Map<String,Object>> onlineBarData = omsOrderService.indexOrderBar();
        map.put("onlineMiniAreaData",omsOrderService.indexOrderMiniArea());

        map.put("store",stmOrderService.indexOrderInit());
        //map.put("storeBarData",stmOrderService.indexOrderBar());
        List<Map<String,Object>> storeBarData = stmOrderService.indexOrderBar();
        map.put("storeMiniAreaData",stmOrderService.indexOrderMiniArea());

        List<Map<String,Object>> barMultidData = new ArrayList<>();
        List<String> barMultidfields = new ArrayList<>();
        Map<String,Object> onlineBarMultidData = new HashMap<>();
        onlineBarMultidData.put("type", "商城");
        onlineBarData.forEach(o->{
            onlineBarMultidData.put(o.get("x").toString(), o.get("y"));
            barMultidfields.add(o.get("x").toString());
        });
        barMultidData.add(onlineBarMultidData);

        Map<String,Object> storeBarMultidData = new HashMap<>();
        storeBarMultidData.put("type", "门店");
        storeBarData.forEach(s->{
            storeBarMultidData.put(s.get("x").toString(), s.get("y"));
        });
        barMultidData.add(storeBarMultidData);
        map.put("barMultidData",barMultidData);
        map.put("barMultidfields",barMultidfields);
        /*List<Map<String,Object>> onlinerankData = omsOrderService.indexOrderRank();
        List<Map<String,Object>> storerankData = stmOrderService.indexOrderRank();*/

        List<Map<String,Object>> onlinerankData = new ArrayList<>();
        List<Map<String,Object>> storerankData = new ArrayList<>();

        List<Map<String,Object>> allRankData = new ArrayList<>();
        allRankData.addAll(onlinerankData);
        allRankData.addAll(storerankData);

        /*List<Map<String,Object>> rankData = new ArrayList<>();
        Map<Object, List<Map<String,Object>>> storeIdRankDataMap =  allRankData.stream().collect(Collectors.groupingBy(q->q.get("storeId")));
        for (Map.Entry<Object, List<Map<String,Object>>> entry : storeIdRankDataMap.entrySet()) {
            List<Map<String,Object>> value = entry.getValue();
            if (value.size() == 1) {
                rankData.addAll(value);
            } else {
                Map<String,Object> data = new HashMap<>();
                data.put("storeId",value.get(0).get("storeId"));
                data.put("name",value.get(0).get("name"));
                data.put("total",BigDecimal.ZERO);
                value.forEach(q->{
                    data.put("total",new BigDecimal(data.get("total").toString()).add(new BigDecimal(q.get("total").toString())));
                });
                rankData.add(data);
            }
        }*/

        List<Map<String,Object>> rankData = allRankData.stream()
                .collect(Collectors.toMap(q->q.get("storeId"), a -> a, (o1,o2)-> {
                    o1.put("total", new BigDecimal(o1.get("total").toString()).add(new BigDecimal(o2.get("total").toString())));
                    return o1;
                })).values().stream().collect(Collectors.toList());

        //rankData.sort(Comparator.comparing(o -> new BigDecimal(o.get("total").toString()))); //升序
        rankData.sort(( o1, o2) -> new BigDecimal(o2.get("total").toString()).compareTo(new BigDecimal(o1.get("total").toString())));

        //log.info("ces:" + rankData.toString());

        if (oConvertUtils.isNotEmpty(rankData) && rankData.size() > 0) {
            List<StmStoreInfo> storeInfos = stmStoreInfoService.list();
            Map<Long, String> storeInfoMaps = storeInfos.stream().collect(Collectors.toMap(StmStoreInfo::getStoreId, StmStoreInfo::getName, (key1, key2) -> key2));
            rankData.forEach(store -> {
                if (oConvertUtils.isNotEmpty(store.get("storeId"))) {
                    if (storeInfoMaps.containsKey(store.get("storeId"))) {
                        store.put("name",storeInfoMaps.get(store.get("storeId")));
                    } else {
                        if (Objects.equals(0L , Long.valueOf(store.get("storeId").toString()))) {
                            store.put("name","线上商城");
                        }
                    }
                }
            });
        }
        map.put("rankData",rankData);
        return Result.ok(map);
    }


    /**
     * 首页统计
     *
     * @return
     */
    @ApiOperation(value="订单-首页统计", notes="订单-首页统计")
    @GetMapping(value = "/indexInitStore")
    public Result<?> indexInitStore(@RequestParam(name="type",required=false) String type) {
        Date date = new Date();
        Date now = new Date();
        //Calendar calendar = Calendar.getInstance();
        //calendar.setTime(date); // 设置为当前时间
        if (oConvertUtils.isNotEmpty(type) && Objects.equals("month" , type )) {
            //calendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH) - 1); // 设置为上一个月
            //calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMinimum(Calendar.DAY_OF_MONTH));//获取上个月的第一天

            date = DateUtil.lastMonth();

        } else {
            //calendar.set(Calendar.DAY_OF_MONTH, calendar.get(Calendar.DAY_OF_MONTH) - 1); // 昨天

            date = DateUtil.yesterday();
        }
        //date = calendar.getTime();
        //log.info(String.format("上一个日期%s",date));
        Date beginTime = DateUtil.beginOfMonth(date);
        Date endTime = DateUtil.endOfMonth(date);

        Date kpiBeginTime = DateUtil.beginOfMonth(now);
        Date kpiEndTime = DateUtil.endOfMonth(now);

        Date nowBeginTime = DateUtil.beginOfMonth(now);
        Date nowEndTime = DateUtil.endOfMonth(now);

        if (Objects.equals("date" , type )) {
            beginTime = DateUtil.beginOfDay(date);
            endTime = DateUtil.endOfDay(date);
            nowBeginTime = DateUtil.beginOfDay(now);
            nowEndTime = DateUtil.endOfDay(now);
        }

        //log.info(String.format("上个开始时间%s,结束时间%s",beginTime,endTime));
        //log.info(String.format("开始时间%s,结束时间%s",nowBeginTime,nowEndTime));

        Map<Long,StmKpiStore> kpiStoreMap = getKpiStoreMap(kpiBeginTime, kpiEndTime);
        List<StmKpiCalendar> kpiCalendars = getKpiCalendar(kpiBeginTime, kpiEndTime);
        BigDecimal rate = BigDecimal.ONE;
        BigDecimal weightAllMonth = kpiCalendars.stream().map(StmKpiCalendar::getRate)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        if (Objects.equals("date" , type )) {
            BigDecimal weight = kpiCalendars.stream().filter(c-> Objects.equals(DateUtils.date2Str(c.getDate(),DateUtils.date_sdf.get()),DateUtils.date2Str(now,DateUtils.date_sdf.get()))).map(StmKpiCalendar::getRate)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            if(BigDecimal.ZERO.compareTo(weightAllMonth)==-1){
                rate = weight.divide(weightAllMonth,3,BigDecimal.ROUND_UP);
            }
        }

        List<StmStoreInfo> storeInfos = getValidStores();
        List<OrderTotalPayAmountVO> prevOnlineTotalPayAmounts = omsOrderService.indexOrderTotalPayAmount(beginTime, endTime);
        List<OrderTotalPayAmountVO> prevStoreTotalPayAmounts = stmOrderService.indexOrderTotalPayAmount(beginTime, endTime);

        List<OrderTotalPayAmountVO> onlineTotalPayAmounts = omsOrderService.indexOrderTotalPayAmount(nowBeginTime, nowEndTime);
        List<OrderTotalPayAmountVO> storeTotalPayAmounts = stmOrderService.indexOrderTotalPayAmount(nowBeginTime, nowEndTime);
        List<HomeOrderVO> homeOrderVOS = new ArrayList<>();
        BigDecimal finalRate = rate;
        storeInfos.forEach(store -> {
            HomeOrderVO vo = new HomeOrderVO();
            vo.setStoreId(store.getStoreId());
            vo.setStoreName(store.getName());
            vo.setKpiAmount(BigDecimal.ZERO);
            vo.setPrevOrderAmount(BigDecimal.ZERO);
            vo.setCurrentOrderAmount(BigDecimal.ZERO);
            vo.setCurrentOnlineAmount(BigDecimal.ZERO);
            vo.setCurrentStoreAmount(BigDecimal.ZERO);
            vo.setFinishRate(BigDecimal.ZERO);
            if (kpiStoreMap.containsKey(store.getStoreId())){
                vo.setKpiAmount(kpiStoreMap.get(store.getStoreId()).getOrderAmount().multiply(finalRate));
            }
            prevOnlineTotalPayAmounts.forEach(p -> {
                if (Objects.equals(p.getStoreId(), store.getStoreId())) {
                    vo.setPrevOrderAmount(vo.getPrevOrderAmount().add(p.getTotalAmount()));
                }
            });
            prevStoreTotalPayAmounts.forEach(ps -> {
                if (Objects.equals(ps.getStoreId(), store.getStoreId())) {
                    vo.setPrevOrderAmount(vo.getPrevOrderAmount().add(ps.getTotalAmount()));
                }
            });
            onlineTotalPayAmounts.forEach(o -> {
                if (Objects.equals(o.getStoreId(), store.getStoreId())) {
                    vo.setCurrentOrderAmount(vo.getCurrentOrderAmount().add(o.getTotalAmount()));
                    vo.setCurrentOnlineAmount(vo.getCurrentOnlineAmount().add(o.getTotalAmount()));
                }
            });
            storeTotalPayAmounts.forEach(s -> {
                if (Objects.equals(s.getStoreId(), store.getStoreId())) {
                    vo.setCurrentOrderAmount(vo.getCurrentOrderAmount().add(s.getTotalAmount()));
                    vo.setCurrentStoreAmount(vo.getCurrentStoreAmount().add(s.getTotalAmount()));
                }
            });
            if(BigDecimal.ZERO.compareTo(vo.getKpiAmount())==-1){
                vo.setFinishRate(calcFinishRate(vo.getKpiAmount(), vo.getCurrentOrderAmount()));
            }
            homeOrderVOS.add(vo);
        });
        return Result.ok(homeOrderVOS);
    }

    BigDecimal calcFinishRate(BigDecimal target, BigDecimal real){
        if(BigDecimal.ZERO.compareTo(real)==0){
            return BigDecimal.ZERO;
        }
        if(BigDecimal.ZERO.compareTo(target)==0){
            return new BigDecimal(100);
        }
        return real.divide(target,3, RoundingMode.HALF_EVEN).multiply(new BigDecimal(100)).setScale(2, RoundingMode.HALF_UP);
    }

    Map<Long,StmKpiStore> getKpiStoreMap(Date beginTime, Date endTime) {
        LambdaQueryWrapper<StmKpiStore> lambdaQueryWrapper = Wrappers.lambdaQuery();
        lambdaQueryWrapper.ge(StmKpiStore::getStartTime, beginTime);
        lambdaQueryWrapper.le(StmKpiStore::getEndTime, endTime);
        List<StmKpiStore> kpiStores = stmKpiStoreService.list(lambdaQueryWrapper);
        return kpiStores.stream().collect(Collectors.toMap(StmKpiStore::getStoreId, Function.identity(), (key1, key2) -> key2));
    }

    List<StmKpiCalendar> getKpiCalendar(Date beginTime, Date endTime) {
        LambdaQueryWrapper<StmKpiCalendar> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.between(StmKpiCalendar::getDate, beginTime, endTime);
        return stmKpiCalendarService.list(queryWrapper);
    }

    List<StmStoreInfo> getValidStores() {
        LambdaQueryWrapper<StmStoreInfo> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.select(StmStoreInfo::getStoreId,StmStoreInfo::getName);
        queryWrapper.ne(StmStoreInfo::getStatus, 0);
        //queryWrapper.ne(StmStoreInfo::getStoreId, 0);
        return stmStoreInfoService.list(queryWrapper);
    }

}
